package com.taxi.driver.data.user;

import com.amap.api.maps.model.LatLng;
import com.qianxx.network.RetrofitRequestTool;
import com.qianxx.utils.SP;
import com.taxi.driver.config.LoginStatus;
import com.taxi.driver.data.entity.AssessmentEntity;
import com.taxi.driver.data.entity.BillEntity;
import com.taxi.driver.data.entity.CancelReasonEntity;
import com.taxi.driver.data.entity.CommentEntity;
import com.taxi.driver.data.entity.ComplainEntity;
import com.taxi.driver.data.entity.DriverEntity;
import com.taxi.driver.data.entity.EvaluateEntity;
import com.taxi.driver.data.entity.FeedBackEntity;
import com.taxi.driver.data.entity.HomeEntity;
import com.taxi.driver.data.entity.MessageEntity;
import com.taxi.driver.data.entity.Mileage;
import com.taxi.driver.data.entity.ProblemEntity;
import com.taxi.driver.data.entity.UpdateMsg;
import com.taxi.driver.data.entity.WithdrawalDetailsEntity;
import com.taxi.driver.data.entity.WithdrawaleRecordEntity;
import com.taxi.driver.data.user.local.UserLocalSource;
import com.taxi.driver.data.user.remote.UserRemoteSource;
import com.taxi.driver.event.UserEvent;
import com.taxi.driver.module.vo.AddressVO;
import com.taxi.driver.socket.SocketEvent;

import org.greenrobot.eventbus.EventBus;

import java.util.List;

import javax.inject.Inject;
import javax.inject.Singleton;

import rx.Observable;

@Singleton
public class UserRepository implements UserSource {

    private final static String SCREEN_LIGHT = "screen_light";
    private final static String VOLUME_TYPE = "volume_type";
    private final static String IMMOBILIZATION_VOLUME_SIZE = "immobilization_volume_size";
    private final static String SYSTEM_VOLUME_SIZE = "system_volume_size";
    private final static String LOGIN_ACCOUNT = "login_account";
    private final static String DRIVER_TYPE = "driver_type";

    private final UserLocalSource mLocalSource;
    private final UserRemoteSource mRemoteSource;
    private final SP mSP;

    @Inject
    public UserRepository(UserLocalSource localSource,
                          UserRemoteSource remoteSource,
                          SP sp) {
        mLocalSource = localSource;
        mRemoteSource = remoteSource;
        mSP = sp;
    }

    @Override
    public Observable<String> reqVerifyCode(String phone) {
        return mRemoteSource.reqVerifyCode(phone);
    }

    @Override
    public Observable<DriverEntity> reqLogin(String phone, String verifyCode) {
        return mRemoteSource.reqLogin(phone, verifyCode)
                .doOnNext(info -> {
                    saveDriverType(info.type);
                    if (info.isFirst != LoginStatus.IS_FIRST) {
                        /* 非首次登录，保存用户信息 */
                        mLocalSource.setUserInfo(info); //保存用户信息到本地
                        saveToken(info.token); //保存token
                        setScreenStatue(true);
                        setImmobilizationVolumeSize(100);
                        EventBus.getDefault().post(new UserEvent(UserEvent.LOGIN)); //发出Event事件，通知界面刷新
                    } else {
                        /* 首次登录，临时保存用户数据 */
                        mLocalSource.setTempDriverEntity(info);
                    }
                });
    }

    @Override
    public Observable<String> reqLogout(double onWorkLng, double onWorkLat, String uploadText) {
        return mRemoteSource.reqLogout(onWorkLng, onWorkLat, uploadText).doOnNext(s -> logout());
    }

    public void logout() {
        mLocalSource.reqLogout(0, 0, null);
        saveToken(""); //清空token
        setScreenStatue(false); //设置screen_light为false
        setVolumeType(false);
        setImmobilizationVolumeSize(0);//设置固定音量为0
        EventBus.getDefault().post(new UserEvent(UserEvent.LOGOUT));
        EventBus.getDefault().post(new SocketEvent(SocketEvent.DISCONNECT)); // 断开长连接
    }

    private void saveToken(String token) {
        RetrofitRequestTool.saveToken(mSP, token);
    }

    @Override
    public Observable<DriverEntity> getUserInfo() {
        if (!isLogin()) {
            return Observable.empty();
        }
        return Observable.concat(mLocalSource.getUserInfo(),
                mRemoteSource.getUserInfo().doOnNext(mLocalSource::setUserInfo))
                .takeFirst(passengerEntity -> passengerEntity != null);
    }

    @Override
    public void refreshUserInfo() {
        mRemoteSource.refreshUserInfo();
        mLocalSource.refreshUserInfo();
    }

    @Override
    public void setUserInfo(DriverEntity entity) {

    }

    @Override
    public boolean isLogin() {
        return mLocalSource.isLogin();
    }

    @Override
    public int getCarLevelType() {
        return mLocalSource.getCarLevelType();
    }

    @Override
    public Observable<List<WithdrawaleRecordEntity>> widthdrawalRecord(int nowPage) {
        return mRemoteSource.widthdrawalRecord(nowPage);
    }

    @Override
    public Observable<BillEntity> reqBills(int nowPage, int dateType, String start, String end, String type) {
        return mRemoteSource.reqBills(nowPage, dateType, start, end, type);
    }

    @Override
    public Observable<List<ProblemEntity>> getProblems() {
        return mRemoteSource.getProblems();
    }

    @Override
    public Observable<List<FeedBackEntity>> getFeedbacks(int nowPage) {
        return mRemoteSource.getFeedbacks(nowPage);
    }

    @Override
    public Observable<String> addFeedback(String title, String content) {
        return mRemoteSource.addFeedback(title, content);
    }

    @Override
    public Observable<WithdrawalDetailsEntity> getWithdrawalInfo(String cashUuid) {
        return mRemoteSource.getWithdrawalInfo(cashUuid);
    }

    @Override
    public Observable<String> withdrawal(String cash, String collectAccount, int collectType, String password) {
        return mRemoteSource.withdrawal(cash, collectAccount, collectType, password);
    }

    @Override
    public Observable<AssessmentEntity> reqAssessment(String startTime, String endTime) {
        return mRemoteSource.reqAssessment(startTime, endTime);
    }

    @Override
    public Observable<EvaluateEntity> getEvaluates() {
        return mRemoteSource.getEvaluates();
    }

    @Override
    public Observable<List<CommentEntity>> getYesterdayEvaluates(int nowPage) {
        return mRemoteSource.getYesterdayEvaluates(nowPage);
    }

    @Override
    public Observable<String> resetPw(String newPsw, String oldPsw) {
        return mRemoteSource.resetPw(newPsw, oldPsw);
    }

    @Override
    public Observable<String> validate(String phone, String idcard, int driverType) {
        return mRemoteSource.validate(phone, idcard, driverType);
    }

    @Override
    public Observable<String> sendCode(String mobile) {
        return mRemoteSource.sendCode(mobile);
    }

    @Override
    public Observable<String> verifyCode(String mobile, String identifyCode) {
        return mRemoteSource.verifyCode(mobile, identifyCode);
    }

    @Override
    public Observable<String> resetPwd(String mobile, String identifyCode, String idcard, String password, int driverType) {
        return mRemoteSource.resetPwd(mobile, identifyCode, idcard, password, driverType);
    }

    @Override
    public void setTempDriverEntity(DriverEntity entity) {
        mLocalSource.setTempDriverEntity(entity);
    }

    @Override
    public DriverEntity getTempDriverEntity() {
        return mLocalSource.getTempDriverEntity();
    }

    @Override
    public Observable<HomeEntity> reqWorkInfo() {
        return mRemoteSource.reqWorkInfo();
    }

    @Override
    public Observable<List<CancelReasonEntity>> reqCancelMsg() {
        return mRemoteSource.reqCancelMsg();
    }

    @Override
    public Observable<List<ComplainEntity>> reqComplainMsg() {
        return mRemoteSource.reqComplainMsg();
    }

    @Override
    public String getLocalDriverUuid() {
        return mLocalSource.getLocalDriverUuid();
    }

    @Override
    public List<AddressVO> getHistoryAddr() {
        return mLocalSource.getHistoryAddr();
    }

    @Override
    public void saveProvince(String province) {
        mLocalSource.saveProvince(province);
    }

    @Override
    public void saveCity(String city) {
        mLocalSource.saveCity(city);
    }

    @Override
    public String getProvince() {
        return mLocalSource.getProvince();
    }

    @Override
    public String getCity() {
        return mLocalSource.getCity();
    }

    @Override
    public void setNetworkStatus(boolean isDisconnect) {
        mLocalSource.setNetworkStatus(isDisconnect);
    }

    @Override
    public Observable<List<MessageEntity>> getMsgList(int nowPage, int pageType) {
        return mRemoteSource.getMsgList(nowPage, pageType);
    }

    @Override
    public Observable<UpdateMsg> updateMsg(String uuid, int status) {
        return mRemoteSource.updateMsg(uuid, status);
    }

    @Override
    public Observable<String> deleteAll() {
        return mRemoteSource.deleteAll();
    }

    @Override
    public Observable<String> deleteMsg(String uuid) {
        return mRemoteSource.deleteMsg(uuid);
    }

    @Override
    public Observable<String> uploadErrorMsg(String errorType, String errorMsg) {
        return mRemoteSource.uploadErrorMsg(errorType, errorMsg);
    }

    /**
     * 保存已行驶里程
     *
     * @param mileage
     * @param mileage
     */
    public void saveMileage(Mileage mileage) {
        mSP.putObject(mileage.getOrderUuid(), mileage);
    }

    /**
     * 获取已行驶里程
     *
     * @return
     */
    public Mileage getMileage(String orderUuid) {
        return mSP.getObject(orderUuid, Mileage.class);
    }

    /**
     * 清除已行驶里程
     *
     * @param orderUuid
     */
    public void cleanMileage(String orderUuid) {
        mSP.removeObject(orderUuid);
    }

    /**
     * 设置屏幕状态
     *
     * @param isBright 是否常亮
     */
    public void setScreenStatue(boolean isBright) {
        mSP.putBoolean(SCREEN_LIGHT, isBright);
    }

    /**
     * 获得屏幕状态
     *
     * @return
     */
    public boolean getScreenStatue() {
        return mSP.getBoolean(SCREEN_LIGHT);
    }

    /**
     * 设置音量类型
     *
     * @param isImmobilizationVolume 是否是固定音量
     */
    public void setVolumeType(boolean isImmobilizationVolume) {
        mSP.putBoolean(VOLUME_TYPE, isImmobilizationVolume);
    }

    /**
     * 是否是固定音量
     *
     * @return
     */
    public boolean isImmobilizationVolum() {
        return mSP.getBoolean(VOLUME_TYPE);
    }

    /**
     * 设置固定音量大小
     *
     * @param size
     */
    public void setImmobilizationVolumeSize(int size) {
        mSP.putInt(IMMOBILIZATION_VOLUME_SIZE, size);
    }

    /**
     * 获得固定音量大小
     *
     * @return
     */
    public int getImmobilizationVolumeSize() {
        return mSP.getInt(IMMOBILIZATION_VOLUME_SIZE);
    }

    /**
     * 设置系统音量大小
     *
     * @param size
     */
    public void setSystemVolumeSize(int size) {
        mSP.putInt(SYSTEM_VOLUME_SIZE, size);
    }

    /**
     * 获得系统音量大小
     *
     * @return
     */
    public int getSystemVolumeSize() {
        return mSP.getInt(SYSTEM_VOLUME_SIZE);
    }

    /**
     * 获得讯飞语音需要的音量
     *
     * @return
     */
    public int getXFVolumeSize() {
        if (isImmobilizationVolum()) {
            return getImmobilizationVolumeSize();
        } else {
            return getSystemVolumeSize();
        }
    }

    /**
     * 保存账号
     *
     * @param account
     */
    public void saveAccount(String account) {
        mSP.putString(LOGIN_ACCOUNT, account);
    }

    /**
     * 获得登录账户
     *
     * @return
     */
    public String getAccount() {
        return mSP.getString(LOGIN_ACCOUNT, "");
    }

    /**
     * 保存司机类型
     *
     * @param type
     */
    public void saveDriverType(int type) {
        mSP.putInt(DRIVER_TYPE, type);
    }

    /**
     * 获得司机类型
     *
     * @return
     */
    public int getDriverType() {
        return mSP.getInt(DRIVER_TYPE);
    }

    /**
     * 保存司机的当前坐标
     *
     * @param latLng
     */
    public void saveLatLng(LatLng latLng) {
        if (latLng == null || latLng.latitude <= 0 || latLng.longitude <= 0) return;
        mSP.putString("lat", String.valueOf(latLng.latitude));
        mSP.putString("lng", String.valueOf(latLng.longitude));
    }

    /**
     * 获取司机当前坐标
     *
     * @return
     */
    public LatLng getLatLng() {
        double lat = getDoubleValue(mSP.getString("lat", "0"));
        double lng = getDoubleValue(mSP.getString("lng", "0"));
        if (lat <= 0 || lng <= 0) return null;
        return new LatLng(lat, lng);
    }

    private double getDoubleValue(String str) {
        try {
            return Double.valueOf(str);
        } catch (Exception e) {
            return 0;
        }
    }
}
